
#include "../GeneralLibrary/Linkage.h"

// 下面是更寄存器在栈中的偏移
R15         =       0x00
R14	        =	    0x08
R13	        =	    0x10
R12	        =	    0x18
R11	        =	    0x20
R10	        =	    0x28
R9	        =	    0x30
R8	        =	    0x38
RBX	        =	    0x40
RCX	        =	    0x48
RDX	        =	    0x50
RSI	        =	    0x58
RDI	        =	    0x60
RBP	        =	    0x68
DS	        =	    0x70
ES	        =	    0x78
RAX	        =	    0x80
FUNC	    =	    0x88
ERRCODE	    =	    0x90
RIP	        =	    0x98
CS	        =	    0xa0
RFLAGS	    =	    0xa8
OLDRSP	    =	    0xb0
OLDSS	    =	    0xb8

// 结构体 Task 的内存偏移
TSK_STATE	=	    0x00
TSK_FLAGS	=	    0x08
TSK_PREEMPT	=	    0x10
TSK_SIGNAL	=	    0x18

// 把所有寄存器全部还原回来
RESTORE_ALL:
	popq	%r15
	popq	%r14
	popq	%r13
	popq	%r12
	popq	%r11
	popq	%r10
	popq	%r9
	popq	%r8
	popq	%rbx
	popq	%rcx
	popq	%rdx
	popq	%rsi
	popq	%rdi
	popq	%rbp
	popq	%rax
	movq	%rax,	%ds
	popq	%rax
	movq	%rax,	%es
	popq	%rax
	addq	$0x10,	%rsp
	iretq

#define GET_CURRENT(reg)	\
	movq	$-32768,reg;	\
	andq	%rsp,	reg

// 返回到异常发生的地方
ret_from_exception:
ENTRY(ret_from_intr)
    movq	$-1,	%rcx
    testq	softIRQStatus(%rip),	%rcx
    jnz	    softIRQHandler
    GET_CURRENT(%rbx)

    movq	TSK_PREEMPT(%rbx),	%rcx		////check preempt
    cmpq	$0,	    %rcx
    jne		RESTORE_ALL

    movq	TSK_FLAGS(%rbx),    %rcx
    testq	$2,	    %rcx
    jnz	    reschedule
	jmp	    RESTORE_ALL	/* need rewrite */

softIRQHandler:
	callq	doSoftIRQ
	GET_CURRENT(%rbx)

	movq	TSK_PREEMPT(%rbx),	%rcx		////check preempt
    cmpq	$0,	%rcx
    jne		RESTORE_ALL

    movq	TSK_FLAGS(%rbx),	%rcx
    testq	$2,	%rcx
    jnz	    reschedule
	jmp	    RESTORE_ALL

reschedule:
	callq	schedule
	jmp	    RESTORE_ALL

// 保存当前程序执行环境，然后调用对应的异常处理函数
error_code:
	pushq	%rax
	movq	%es,	%rax
	pushq	%rax
	movq	%ds,	%rax
	pushq	%rax
	xorq	%rax,	%rax

	pushq	%rbp
	pushq	%rdi
	pushq	%rsi
	pushq	%rdx
	pushq	%rcx
	pushq	%rbx
	pushq	%r8
	pushq	%r9
	pushq	%r10
	pushq	%r11
	pushq	%r12
	pushq	%r13
	pushq	%r14
	pushq	%r15

	cld
	movq	ERRCODE(%rsp),	%rsi
	movq	FUNC(%rsp),	%rdx

	movq	$0x10,	%rdi
	movq	%rdi,	%ds
	movq	%rdi,	%es

	movq	%rsp,	%rdi

	callq 	*%rdx

	jmp	ret_from_exception

// 除法错误
ENTRY(divide_error)
	pushq	$0
	pushq	%rax
	leaq	do_divide_error(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 调试异常
ENTRY(debug)
	pushq	$0
	pushq	%rax
	leaq	do_debug(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 不可屏蔽中断异常
ENTRY(nmi)
    pushq	$0
	pushq	%rax
	cld;
	pushq	%rax;

	pushq	%rax
	movq	%es,	%rax
	pushq	%rax
	movq	%ds,	%rax
	pushq	%rax
	xorq	%rax,	%rax

	pushq	%rbp;
	pushq	%rdi;
	pushq	%rsi;
	pushq	%rdx;
	pushq	%rcx;
	pushq	%rbx;
	pushq	%r8;
	pushq	%r9;
	pushq	%r10;
	pushq	%r11;
	pushq	%r12;
	pushq	%r13;
	pushq	%r14;
	pushq	%r15;

	movq	$0x10,	%rdx;
	movq	%rdx,	%ds;
	movq	%rdx,	%es;

	movq	$0,	%rsi
	movq	%rsp,	%rdi

	callq	do_nmi

	jmp	RESTORE_ALL

// int3 中断异常
ENTRY(int3)
	pushq	$0
	pushq	%rax
	leaq	do_int3(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 溢出
ENTRY(overflow)
	pushq	$0
	pushq	%rax
	leaq	do_overflow(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 边界监测中断
ENTRY(bounds)
	pushq	$0
	pushq	%rax
	leaq	do_bounds(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 无效操作码
ENTRY(invalid_opcode)
	pushq	$0
	pushq	%rax
	leaq	do_invalid_opcode(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 设备不可用
ENTRY(device_not_available)	/* need rewrite */
	pushq	$0
	pushq	%rax
	leaq	do_device_not_available(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 异常终止，也就是双异常
ENTRY(double_fault)
    pushq	$0
	pushq	%rax
	leaq	do_double_fault(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 协处理器段溢出异常
ENTRY(coprocessor_segment_overrun)
	pushq	$0
	pushq	%rax
	leaq	do_coprocessor_segment_overrun(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 无效的TSS异常
ENTRY(invalid_TSS)
    pushq	$0
	pushq	%rax
	leaq	do_invalid_TSS(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 缺段中断异常
ENTRY(segment_not_present)
    pushq	$0
	pushq	%rax
	leaq	do_segment_not_present(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 堆栈异常
ENTRY(stack_segment_fault)
    pushq	$0
	pushq	%rax
	leaq	do_stack_segment_fault(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 一般保护异常
ENTRY(general_protection)
	pushq	%rax
	leaq	do_general_protection(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 页异常
ENTRY(page_fault)
	pushq	%rax
	leaq	do_page_fault(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// x87状态寄存器错误
ENTRY(x87_FPU_error)
	pushq	$0
	pushq	%rax
	leaq	do_x87_FPU_error(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 	对齐检查中断
ENTRY(alignment_check)
    pushq   $0
	pushq	%rax
	leaq	do_alignment_check(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 机器检查
ENTRY(machine_check)
	pushq	$0
	pushq	%rax
	leaq	do_machine_check(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 篇幅过长，是Intel规定的 19 异常
ENTRY(SIMD_exception)
	pushq	$0
	pushq	%rax
	leaq	do_SIMD_exception(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code

// 虚拟机异常
ENTRY(virtualization_exception)
	pushq	$0
	pushq	%rax
	leaq	do_virtualization_exception(%rip),	%rax
	xchgq	%rax,	(%rsp)
	jmp	error_code